package com.jht.bletool2java.characteristic.ftms;

import android.bluetooth.BluetoothGattCharacteristic;
import android.util.Log;

import androidx.annotation.Keep;

import com.jht.bletool2java.characteristic.TranslateData;
import com.jht.bletool2java.util.ByteUtil;
import com.jht.bletool2java.util.ComputerUtil;

import top.codestudy.annotation_uuid.MyUUID;

//判断处理ok
@Keep
@MyUUID(uuid = "00002acf-0000-1000-8000-00805f9b34fb")
public class StepClimberData implements TranslateData {
    private static StepClimberData data;
    private final String TAG = "StepClimberData";
    byte[] value1;
    private byte[] flags = new byte[2];
    private byte[] floors;
    private byte[] step_count;
    private byte[] step_per_minute;
    private byte[] average_Step_Rate;
    private byte[] positive_elevation_gain;
    private byte[] total_energy;
    private byte[] energy_per_hour;
    private byte[] energy_per_minute;
    private byte[] heart_rate;
    private byte[] metabolic_equivalent;
    private byte[] elapsed_time;
    private byte[] remaining_time;
    private boolean floorsAndStepCount = false;
    private boolean stepPerMinute = false;
    private boolean averageStepRate = false;
    private boolean positiveElevationGain = false;
    private boolean energy = false;
    private boolean heartRate = false;
    private boolean metabolic = false;
    private boolean elapsedTime = false;
    private boolean remainingTime = false;
    private int expect_data_length = 0;
    private byte[] valueData;
    //是否是非法数据
    private boolean isInvalidData = false;

    public StepClimberData() {
    }

    public StepClimberData(BluetoothGattCharacteristic characteristic) {
        byte[] value = characteristic.getValue();
        valueData = value;
        value1 = value;
        parseData(value);
        for (int i = 0; i < value.length; i++) {
            Log.i(TAG, "StepClimberData: i = " + i + "; ox" + Integer.toHexString(ByteUtil.byte1ToInt(value[i])));
        }
    }

    public static StepClimberData getInstance() {
        data = new StepClimberData();
        return data;
    }

    public void parseData(byte[] buffer) {
        Log.i(TAG, "parseData: buffer.length " + buffer.length);
        System.arraycopy(buffer, 0, flags, 0, 2);
        checkEachFieldIfSupported();
        parseEachSupportedFeature(buffer);

    }

    private void checkEachFieldIfSupported() {

        byte firstbyte = (byte) (flags[0] ^ 0xFE); // 0xFE means all features are supported in 1st byte;
        byte secondbyte = (byte) (flags[1] ^ 0xFF); // 0xFF mean all features are supported in 2nd byte;

        expect_data_length = 2;

        if (isBitZero(firstbyte, 0)) {
            //floorsAndStepCount is supported
            floorsAndStepCount = true;
            floors = new byte[2];
            step_count = new byte[2];
            expect_data_length += 4;
            Log.d(TAG, "floorsAndStepCount is supported");
        } else {
            Log.e(TAG, "数据过多！显示数据不可靠！");
        }
        if (isBitZero(firstbyte, 1)) {
            //stepPerMinute is supported
            stepPerMinute = true;
            step_per_minute = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "Step per Minute is supported");
        }

        if (isBitZero(firstbyte, 2)) {
            //averageStepRate is supported
            averageStepRate = true;
            average_Step_Rate = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "averageStepRate is supported");
        }
        if (isBitZero(firstbyte, 3)) {
            //Positive Elevation Gain is supported
            positiveElevationGain = true;
            positive_elevation_gain = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "Positive Elevation Gain is supported");
        }
        if (isBitZero(firstbyte, 4)) {
            //Expended Energy is supported
            energy = true;
            total_energy = new byte[2];
            energy_per_hour = new byte[2];
            energy_per_minute = new byte[1];
            expect_data_length += 5;
            Log.d(TAG, "Expended Energy is supported");
        }
        if (isBitZero(firstbyte, 5)) {
            // heartRate are supported
            heartRate = true;
            heart_rate = new byte[1];
            expect_data_length += 1;
            Log.d(TAG, "heartRate is supported");
        }

        if (isBitZero(firstbyte, 6)) {
            //metabolic is supported
            metabolic = true;
            metabolic_equivalent = new byte[1];
            expect_data_length += 1;
            Log.d(TAG, "metabolic is supported");
        }

        if (isBitZero(firstbyte, 7)) {
            //elapsed time is supported
            elapsedTime = true;
            elapsed_time = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "elapsed time is supported");
        }
        if (isBitZero(secondbyte, 0)) {
            //remaining time is supported
            remainingTime = true;
            remaining_time = new byte[2];
            expect_data_length += 2;
            Log.d(TAG, "remaining time is supported");
        }


    }

    /**
     * @param value, the xor result, 0 means feature is supported. 1 means feature is not supported
     * @param bit,   the bit of value to check
     * @return
     */
    private boolean isBitZero(byte value, int bit) {
        int power2 = (int) Math.pow(2, bit);
        int tmp = value & power2;
        if (tmp == 0) {
            return true;
        } else {
            return false;
        }
    }

    private void parseEachSupportedFeature(byte[] buffer) {
        if (buffer.length < expect_data_length) {
            isInvalidData = true;
            Log.d(TAG, "buffer length is " + buffer.length);
            Log.d(TAG, "expect data length is " + expect_data_length);
            return;
        }

        int startIndex = 2;
        if (floorsAndStepCount) {
            System.arraycopy(buffer, startIndex, floors, 0, 2);
            startIndex += 2;
            System.arraycopy(buffer, startIndex, step_count, 0, 2);
            startIndex += 2;
        }
        if (stepPerMinute) {
            System.arraycopy(buffer, startIndex, step_per_minute, 0, 2);
            startIndex += 2;
        }
        if (averageStepRate) {
            System.arraycopy(buffer, startIndex, average_Step_Rate, 0, 2);
            startIndex += 2;
        }
        if (positiveElevationGain) {
            System.arraycopy(buffer, startIndex, positive_elevation_gain, 0, 2);
            startIndex += 2;
        }
        if (energy) {
            System.arraycopy(buffer, startIndex, total_energy, 0, 2);
            startIndex += 2;
            System.arraycopy(buffer, startIndex, energy_per_hour, 0, 2);
            startIndex += 2;
            System.arraycopy(buffer, startIndex, energy_per_minute, 0, 1);
            startIndex += 1;
        }
        if (heartRate) {
            System.arraycopy(buffer, startIndex, heart_rate, 0, 1);
            startIndex += 1;
        }
        if (metabolic) {
            System.arraycopy(buffer, startIndex, metabolic_equivalent, 0, 1);
            startIndex += 1;
        }
        if (elapsedTime) {
            System.arraycopy(buffer, startIndex, elapsed_time, 0, 2);
            startIndex += 2;
        }
        if (remainingTime) {
            System.arraycopy(buffer, startIndex, remaining_time, 0, 2);
        }
    }

    public int getFloors() {
        if (floorsAndStepCount) {
            return ByteUtil.bytes2ToInt(floors, 0);
        } else {
            return -9999;
        }
    }

    public int getStepCount() {
        if (floorsAndStepCount) {
            return ByteUtil.bytes2ToInt(step_count, 0);
        } else {
            return -9999;
        }
    }

    public int getStepPerMinute() {
        if (stepPerMinute) {
            return ByteUtil.bytes2ToInt(step_per_minute, 0);
        } else {
            return -9999;
        }
    }

    public int getAverageStepRate() {

        if (averageStepRate) {
            return ByteUtil.bytes2ToInt(average_Step_Rate, 0);
        } else {
            return -9999;
        }
    }

    public int getPositiveElevationGain() {

        if (positiveElevationGain) {
            return ByteUtil.bytes2ToInt(positive_elevation_gain, 0);
        } else {
            return -9999;
        }
    }

    public int getTotalEnergy() {
        if (energy) {
            return ByteUtil.bytes2ToInt(total_energy, 0);
        } else {
            return -9999;
        }
    }

    public int getEnergyPerHour() {
        if (energy) {
            return ByteUtil.bytes2ToInt(energy_per_hour, 0);
        } else {
            return -9999;
        }
    }

    public int getEnergyPerMinute() {
        if (energy) {
            return ByteUtil.byte1ToInt(energy_per_minute[0]);
        } else {
            return -9999;
        }
    }

    public int getHeartRate() {
        if (heartRate) {
            return ByteUtil.byte1ToInt(heart_rate[0]);
        } else {
            return -9999;
        }
    }

    public double getMetabolicEquivalent() {
        if (metabolic) {
            return ComputerUtil.multiply(ByteUtil.byte1ToInt(metabolic_equivalent[0]), "0.1");
        } else {
            return -9999;
        }
    }

    public int getElapedTime() {
        if (elapsedTime) {
            return ByteUtil.bytes2ToInt(elapsed_time, 0);
        } else {
            return -9999;
        }
    }

    public int getRemainingTime() {
        if (remainingTime) {
            return ByteUtil.bytes2ToInt(remaining_time, 0);
        } else {
            return -9999;
        }
    }

    public String convert2String() {
        return "Floors :  " + getFloors()
                + "   ; \n StepCount :  " + getStepCount()
                + "   ; \n PositiveElevationGain :  " + getPositiveElevationGain()
                + "   m ; \n TotalEnergy :  " + getTotalEnergy()
                + "  Calorie ;\n Energy Per Minute : " + getEnergyPerMinute()
                + "  Calorie ;\n Energy Per Hour : " + getEnergyPerHour()
                + "   Calorie ; \n HeartRate :  " + getHeartRate()
                + "   bpm ; \n elapsed time :  " + getElapedTime()
                + "   second; \n StepPerMinute :   " + getStepPerMinute()
                + "   step_per_minute ; \n AverageStepRate :   " + getAverageStepRate()
                + "   step_per_minute; \n RemainingTime :   " + getRemainingTime()
                + "   second;\n Metabolic Equivalent : " + getMetabolicEquivalent()
                + ";\n "
                ;
    }

    @Override
    public String merge(TranslateData translateData) {
        StepClimberData temp = (StepClimberData) translateData;
        if (temp.floorsAndStepCount) {
            this.floors = temp.floors;
            this.step_count = temp.step_count;
            this.floorsAndStepCount = true;
        }
        if (temp.stepPerMinute) {
            this.step_per_minute = temp.step_per_minute;
            this.stepPerMinute = true;
        }
        if (temp.averageStepRate) {
            this.average_Step_Rate = temp.average_Step_Rate;
            this.averageStepRate = true;
        }
        if (temp.positiveElevationGain) {
            this.positive_elevation_gain = temp.positive_elevation_gain;
            this.positiveElevationGain = true;

        }
        if (temp.energy) {
            this.total_energy = temp.total_energy;
            this.energy_per_hour = temp.energy_per_hour;
            this.energy_per_minute = temp.energy_per_minute;
            this.energy = true;

        }
        if (temp.heartRate) {
            this.heart_rate = temp.heart_rate;
            this.heartRate = true;
        }
        if (temp.metabolic) {
            this.metabolic_equivalent = temp.metabolic_equivalent;
            this.metabolic = true;
        }
        if (temp.elapsedTime) {
            this.elapsed_time = temp.elapsed_time;
            this.elapsedTime = true;
        }
        if (temp.remainingTime) {
            this.remaining_time = temp.remaining_time;
            this.remainingTime = true;
        }

        return null;
    }

    @Override
    public boolean hasMoreData() {
        return !floorsAndStepCount;
    }

    @Override
    public byte[] getData() {
        return valueData;
    }

    @Override
    public boolean isInvalidData() {
        return isInvalidData;
    }

    @Override
    public void parseData(BluetoothGattCharacteristic characteristic, byte[] value) {
        init();
        valueData = value;
        value1 = value;
        parseData(value);
        for (int i = 0; i < value.length; i++) {
            Log.i(TAG, "StepClimberData: i = " + i + "; ox" + Integer.toHexString(ByteUtil.byte1ToInt(value[i])));
        }
    }

    private void init() {
        floorsAndStepCount = false;
        stepPerMinute = false;
        averageStepRate = false;
        positiveElevationGain = false;
        energy = false;
        heartRate = false;
        metabolic = false;
        elapsedTime = false;
        remainingTime = false;
        isInvalidData = false;
        expect_data_length = 0;
    }
}
